package top.bbman.boot.redis.bean;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import top.bbman.boot.logger.LogConstant;
import top.bbman.boot.redis.constant.PeaRedisBeanName;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.Objects;
import java.util.Set;

/**
 * list operations
 *
 * @author 祥霸
 * @version 1.0
 */
@Component(PeaRedisBeanName.DIY_SET_REDIS)
public class PeaSetRedis<E> {


    @PostConstruct
    private void init() {
        LogConstant.bbManRedis.info("init set redis");
    }

    @Resource
    private RedisTemplate<String, E> redisTemplate;

    /**
     * Returns the number of elements in this set (its cardinality).  If this
     * set contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
     * <tt>Integer.MAX_VALUE</tt>.
     *
     * @param key redis key
     * @return the number of elements in this set (its cardinality)
     */
    public Long size(String key) {
        return redisTemplate.opsForSet().size(key);
    }

    /**
     * Returns <tt>true</tt> if this set contains no elements.
     *
     * @param key redis key
     * @return <tt>true</tt> if this set contains no elements
     */
    public boolean isEmpty(String key){
        return this.size(key) == 0L;
    }

    /**
     * Returns <tt>true</tt> if this set contains the specified element.
     * More formally, returns <tt>true</tt> if and only if this set
     * contains an element <tt>e</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
     *
     * @param key redis key
     * @param o element whose presence in this set is to be tested
     * @return <tt>true</tt> if this set contains the specified element
     */
    public Boolean contains(String key, E o) {
        return redisTemplate.opsForSet().isMember(key, o);
    }


    /**
     * Returns an array containing all of the elements in this set.
     * If this set makes any guarantees as to what order its elements
     * are returned by its iterator, this method must return the
     * elements in the same order.
     *
     * @param key redis key
     * @return an array containing all the elements in this set
     */
    public Object[] toArray(String key) {
        return this.getAll(key).toArray();
    }

    /**
     * Adds the specified element to this set if it is not already present
     * (optional operation).  More formally, adds the specified element
     * <tt>e</tt> to this set if the set contains no element <tt>e2</tt>
     * such that
     * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
     * If this set already contains the element, the call leaves the set
     * unchanged and returns <tt>false</tt>.  In combination with the
     * restriction on constructors, this ensures that sets never contain
     * duplicate elements.
     *
     * @param key redis key
     * @param e element to be added to this set
     * @return <tt>true</tt> if this set did not already contain the specified
     *         element
     */
    public boolean add(String key, E e) {
        Long index = redisTemplate.opsForSet().add(key, e);
        return Objects.nonNull(index) && index > 0L;
    }

    /**
     * Removes the specified element from this set if it is present
     * (optional operation).  More formally, removes an element <tt>e</tt>
     * such that
     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>, if
     * this set contains such an element.  Returns <tt>true</tt> if this set
     * contained the element (or equivalently, if this set changed as a
     * result of the call).  (This set will not contain the element once the
     * call returns.)
     *
     * @param key redis key
     * @param o object to be removed from this set, if present
     * @return <tt>true</tt> if this set contained the specified element
     */
    public boolean remove(String key, E o) {
        Long count = redisTemplate.opsForSet().remove(key, o);
        return Objects.nonNull(count) && count > 0L;
    }

    /**
     * Adds all of the elements in the specified collection to this set if
     * they're not already present (optional operation).  If the specified
     * collection is also a set, the <tt>addAll</tt> operation effectively
     * modifies this set so that its value is the <i>union</i> of the two
     * sets.  The behavior of this operation is undefined if the specified
     * collection is modified while the operation is in progress.
     *
     * @param key redis key
     * @param c collection containing elements to be added to this set
     * @return <tt>true</tt> if this set changed as a result of the call
     */
    public boolean addAll(String key, Collection<?> c) {
        E[] arr = (E[]) c.toArray();
        Long index = redisTemplate.opsForSet().add(key, arr);
        return Objects.nonNull(index) && index > 0L;
    }

    /**
     * Removes from this set all of its elements that are contained in the
     * specified collection (optional operation).  If the specified
     * collection is also a set, this operation effectively modifies this
     * set so that its value is the <i>asymmetric set difference</i> of
     * the two sets.
     *
     * @param key redis key
     * @param c collection containing elements to be removed from this set
     * @return <tt>true</tt> if this set changed as a result of the call
     */
    boolean removeAll(String key, Collection<?> c) {
        E[] arr = (E[]) c.toArray();
        Long count = redisTemplate.opsForSet().remove(key, arr);
        return Objects.nonNull(count) && count > 0L;
    }

    public Set<E> getAll(String key) {
        return redisTemplate.opsForSet().members(key);
    }
}
